package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import org.jsola.common.DateKit8;
import org.jsola.common.StrKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.CalculatePayConstant;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.SalaryCalculateRuleDO;
import org.jsola.hr.entity.salary.*;
import org.jsola.hr.query.CalculatePayQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.CalculatePayVO;
import org.jsola.hr.vo.SalaryCalculateRuleGroupVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author wu
 */
@Service("hrCalculatePayTwoServiceImpl")
public class CalculatePayTwoServiceImpl implements ICalculatePayTwoService {

    @Autowired
    private ISalaryCalculateRuleService salaryCalculateRuleService;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private ISalaryCalculateRuleGroupService salaryCalculateRuleGroupService;
    @Autowired
    private ICalculatePayService calculatePayService;

    @Override
    public CalculatePayVO calculatePay(CalculatePayQuery calculatePayQuery, TokenUser tokenUser) {
        // 根据员工id查询员工信息
        EmpInfoDO empInfoDO = empInfoService.selectDOById(calculatePayQuery.getEmpInfoId(), tokenUser.getSiteId());
        ParamException.notNull(empInfoDO, "员工信息不存在或已删除，请稍后重试或联系管理员");
//        if (StrKit.isNotEmpty(empInfoDO.getSalaryRuleId())) {
//            // 根据规则组id查找规则（排序）
//            List<SalaryCalculateRuleDO> salaryCalculateRuleDOList = salaryCalculateRuleService
//                    .selectByGroupId(empInfoDO.getSalaryRuleId(), new TokenUser("", tokenUser.getSiteId()));
//            if (CollectionUtils.isEmpty(salaryCalculateRuleDOList)) {
//                // 如果规则组内没有规则，则调用老方法使用老数据
//                return calculatePayService.calculatePay(calculatePayQuery, tokenUser.getSiteId());
//            }
//        }

        // 查询参数
        BigDecimal manHour = calculatePayQuery.getManHour();
        BigDecimal manDay = calculatePayQuery.getManDay();
//        ParamException.isFalse(manHour.intValue() > 744, "工时不能超过744个小时");
        String month = calculatePayQuery.getThisStartMonth() < 10 ?
                "0" + calculatePayQuery.getThisStartMonth() : calculatePayQuery.getThisStartMonth() + "";
        String thisStartTime = calculatePayQuery.getThisStartYear() + "-" + month + "-01";
        BigDecimal historyManHour = calculatePayQuery.getHistoryManHour();
        ParamException.notNull(historyManHour, "历史工时不能为空");
        String entryTime = DateKit8.format(empInfoDO.getJoinDate(), "yyyy-MM-dd");
        ParamException.notNull(entryTime, "入职时间不能为空");
        String leaveOfficeTime = DateKit8.format(empInfoDO.getLeaveDate(), "yyyy-MM-dd");
        BigDecimal historyDay = calculatePayQuery.getHistoryDay() == null ?
                new BigDecimal("0") : calculatePayQuery.getHistoryDay();
        BigDecimal workerSalary = calculatePayQuery.getWorkerSalary();

        CalculatePayVO calculatePayVO = new CalculatePayVO();
        calculatePayVO.setAmount(new BigDecimal("0"));
        calculatePayVO.setServiceFee(new BigDecimal("0"));
        calculatePayVO.setSpecialFee(new BigDecimal("0"));
        calculatePayVO.setServiceFeeSpecialFee(new BigDecimal("0"));
        calculatePayVO.setServiceFeeWorkTimeRake(new BigDecimal("0"));
        calculatePayVO.setWorkTimeRake(new BigDecimal("0"));

        // 计算薪资
        if (StrKit.isNotEmpty(empInfoDO.getSalaryRuleId())) {
            calculatePay(calculatePayVO, empInfoDO.getSalaryRuleId(), tokenUser,
                    manHour, manDay, thisStartTime, historyManHour, historyDay, entryTime,
                    leaveOfficeTime, calculatePayQuery.getIsAmountRedPacket(), null);


        }
        // 计算劳务费
        if (StrKit.isNotEmpty(empInfoDO.getServiceFeeRuleId())) {
            calculatePay(calculatePayVO, empInfoDO.getServiceFeeRuleId(), tokenUser,
                    manHour, manDay, thisStartTime, historyManHour, historyDay, entryTime,
                    leaveOfficeTime, calculatePayQuery.getIsServiceFeeRedPacket(), workerSalary);

        }
        return calculatePayVO;
    }

    @Override
    public CalculatePayVO calculatePay(String empInfoId, BigDecimal manHour,
                                       BigDecimal manDay, Integer year, Integer month,
                                       BigDecimal historyManHour, BigDecimal historyDay,
                                       String isAmountRedPacket, String isServiceFeeRedPacket,
                                       BigDecimal workerSalary, TokenUser tokenUser) {

        CalculatePayQuery calculatePayQuery = new CalculatePayQuery();
        ParamException.isFalse(StrKit.isEmpty(empInfoId), "员工id不能为空");
        ParamException.isFalse(Objects.isNull(manHour), "工时不能为空");
        ParamException.isFalse(Objects.isNull(manDay), "出勤天数不能为空");
        ParamException.isFalse(Objects.isNull(year), "本次开始时间(年)不能为空");
        ParamException.isFalse(Objects.isNull(month), "本次开始时间（月）不能为空");
        ParamException.isFalse(Objects.isNull(historyManHour), "历史工时不能为空");
        ParamException.isFalse(Objects.isNull(historyDay), "历史出勤天数不能为空");
        calculatePayQuery.setEmpInfoId(empInfoId);
        calculatePayQuery.setManHour(manHour);
        calculatePayQuery.setManDay(manDay);
        calculatePayQuery.setThisStartYear(year);
        calculatePayQuery.setThisStartMonth(month);
        calculatePayQuery.setHistoryManHour(historyManHour);
        calculatePayQuery.setHistoryDay(historyDay);
        calculatePayQuery.setIsAmountRedPacket(isAmountRedPacket);
        calculatePayQuery.setIsServiceFeeRedPacket(isServiceFeeRedPacket);
        calculatePayQuery.setWorkerSalary(workerSalary);
        return calculatePay(calculatePayQuery, tokenUser);
    }

    /**
     * 根据规则id计算薪资或劳务费
     *
     * @param calculatePayVO             返回的参数
     * @param salaryCalculateRuleGroupId 规则组id
     * @param tokenUser                  当前用户
     * @param manHour                    工时
     * @param manDay                     工作天数
     * @param thisStartTime              本次开始时间
     * @param historyManHour             历史工时
     * @param historyDay                 历史出勤天数
     * @param entryTime                  入职日期
     * @param leaveOfficeTime            离职日期
     * @param isRedPacket                是否发放过红包：格式：List<RedPacketRecord>
     * @param workerSalary               工人工资（计算劳务费抽成使用）
     */
    private void calculatePay(CalculatePayVO calculatePayVO, String salaryCalculateRuleGroupId,
                              TokenUser tokenUser, BigDecimal manHour,
                              BigDecimal manDay, String thisStartTime,
                              BigDecimal historyManHour, BigDecimal historyDay,
                              String entryTime, String leaveOfficeTime,
                              String isRedPacket, BigDecimal workerSalary) {
        // 查找规则组信息
        SalaryCalculateRuleGroupVO salaryCalculateRuleGroupVO =
                salaryCalculateRuleGroupService.selectById(salaryCalculateRuleGroupId, tokenUser.getSiteId());
        if (Objects.isNull(salaryCalculateRuleGroupVO)) {
            return;
        }

        // 计算本次结束时间
        Date thisEndDate = DateKit8.addMonths(DateKit8.parseDate(thisStartTime), 1);
        thisEndDate = DateKit8.addDays(thisEndDate, -1);
        String thisEndTime = DateKit8.format(thisEndDate, "yyyy-MM-dd");
        if (leaveOfficeTime != null) {
            Date leaveOfficeDate = DateKit8.parseDate(leaveOfficeTime);
            if (leaveOfficeDate.getTime() < thisEndDate.getTime()) {
                thisEndTime = DateKit8.format(leaveOfficeDate, "yyyy-MM-dd");
            }
        }
        // 判断本次计算时 是否离职  如果离职判断是否满月
        boolean thisLeaveOffice = false;
        boolean meetMonth = true;
        if (StrKit.isNotEmpty(leaveOfficeTime)
                && DateKit8.parseDate(leaveOfficeTime).getTime() >= DateKit8.parseDate(thisStartTime).getTime()
                && DateKit8.parseDate(leaveOfficeTime).getTime() <= thisEndDate.getTime()) {
            thisLeaveOffice = true;
            if (Integer.parseInt(leaveOfficeTime.substring(leaveOfficeTime.length() - 2))
                    < Integer.parseInt(entryTime.substring(entryTime.length() - 2))) {
                meetMonth = false;
            }
            if (leaveOfficeTime.substring(5, 7).equals(entryTime.substring(5, 7))) {
                // 同一月份  当月不满月
                meetMonth = false;
            }
        }
        // 查询计算规则
        List<SalaryCalculateRuleDO> salaryCalculateRuleDOList = salaryCalculateRuleService.selectByGroupId(salaryCalculateRuleGroupId, tokenUser);
        if (salaryCalculateRuleGroupVO.getRuleType() == null) {
            throw new ParamException("规则没有类型，请联系管理员查看原因！");
        }
        String errorMsg = salaryCalculateRuleGroupVO.getRuleType().equals(CalculatePayConstant.RULE_TYPE_MAN_HOUR) ?
                "请完善工价规则后再定薪。" : "请完善招工劳务费规则后再定薪";
        ParamException.isFalse(CollectionUtils.isEmpty(salaryCalculateRuleDOList),
                "【" + salaryCalculateRuleGroupVO.getName() + "】规则为空，" + errorMsg);
        // 判断是工价还是劳务费
        int ruleType = salaryCalculateRuleDOList.get(0).getRuleType();
        // 匹配使用哪些规则
        List<SalaryCalculateRuleDO> salaryCalculateRuleUseDOList = new ArrayList<>();
        matchingRule(salaryCalculateRuleDOList, salaryCalculateRuleUseDOList, thisEndTime, entryTime,
                manHour, historyManHour, manDay, historyDay, thisStartTime);
        // 没有匹配到对应的时间段则直接返回
        if (CollectionUtils.isEmpty(salaryCalculateRuleUseDOList)) {
            return;
        }
        // 构造分段List
        List<BigDecimal> numbers = new ArrayList<>();
        List<BigDecimal> numbersLeave = new ArrayList<>();
        List<BigDecimal> proportionNumberDay = new ArrayList<>();
        List<BigDecimal> proportionNumberHour = new ArrayList<>();
        List<BigDecimal> proportionNumberLeaveDay = new ArrayList<>();
        List<BigDecimal> proportionNumberLeaveHour = new ArrayList<>();
        subsection(salaryCalculateRuleUseDOList, manHour, historyManHour, manDay, historyDay,
                numbers, numbersLeave, proportionNumberDay, proportionNumberHour,
                proportionNumberLeaveDay, proportionNumberLeaveHour);
        // 构建红包发放记录List
        List<RedPacketRecord> redPacketRecordList = new ArrayList<>();
        if (StrKit.isNotEmpty(isRedPacket) && isRedPacket.contains("[")) {
            redPacketRecordList = JSON.parseArray(isRedPacket, RedPacketRecord.class);
        }
        // 根据符合的规则开始计算薪资或劳务费
        // 计算薪资
        // 累计的薪资
        BigDecimal initialPaySum = new BigDecimal("0");
        // 累计的红包
        BigDecimal redPacketSum = new BigDecimal("0");
        // 累计的扣款
        BigDecimal withholdSum = new BigDecimal("0");
        for (int i = 0; i < salaryCalculateRuleUseDOList.size(); i++) {
            SalaryCalculateRuleDO salaryCalculateRuleDO = salaryCalculateRuleUseDOList.get(i);
            // 构建工价规则List
            List<HourAmountRule> hourAmountRuleList = new ArrayList<>();
            if (StrKit.isNotEmpty(salaryCalculateRuleDO.getHourAmountRule())) {
                hourAmountRuleList = JSON.parseArray(salaryCalculateRuleDO.getHourAmountRule(), HourAmountRule.class);
            }
            // 构建离职规则List
            List<LeaveOfficeRule> leaveOfficeRuleList = new ArrayList<>();
            if (StrKit.isNotEmpty(salaryCalculateRuleDO.getLeaveOfficeRule())) {
                leaveOfficeRuleList = JSON.parseArray(salaryCalculateRuleDO.getLeaveOfficeRule(), LeaveOfficeRule.class);
            }
            // 构建红包规则List
            List<RedPacketRule> redPacketRuleList = new ArrayList<>();
            RedPacketRule normalPacketRule = null;
            RedPacketRule leaveRedPacketRule = null;
            if (StrKit.isNotEmpty(salaryCalculateRuleDO.getRedPacketRule())) {
                redPacketRuleList = JSON.parseArray(salaryCalculateRuleDO.getRedPacketRule(), RedPacketRule.class);
            }
            for (RedPacketRule redPacketRule : redPacketRuleList) {
                if (CalculatePayConstant.CALCULATE_TYPE_NORMAL.equals(redPacketRule.getCalculateType())) {
                    normalPacketRule = redPacketRule;
                } else {
                    leaveRedPacketRule = redPacketRule;
                }
            }
            // 离职扣款(工价规则计算时需要)
            BigDecimal withhold = new BigDecimal("0");
            if (salaryCalculateRuleDO.getSpecialCost() != null && CalculatePayConstant.RULE_TYPE_MAN_HOUR.equals(ruleType)) {
                withhold = new BigDecimal(salaryCalculateRuleDO.getSpecialCost() + "")
                        .divide(new BigDecimal("10000"), 4, BigDecimal.ROUND_DOWN);
            }
            // 判断是否使用离职规则
            int dissatisfyMonth = salaryCalculateRuleDO.getDissatisfyMonth() == null ?
                    0 : salaryCalculateRuleDO.getDissatisfyMonth();
            // （当前月是离职月）并且（离职规则设置了）并且（不满月限制没有勾选 或者（不满月限制勾选了且当然人员的确没有满月））
            // 进入离职规则计算
            if (thisLeaveOffice && !CollectionUtils.isEmpty(leaveOfficeRuleList)
                    && (dissatisfyMonth == 0 || (dissatisfyMonth == 1 && !meetMonth))) {
                BigDecimal redNumber = new BigDecimal(0);
                if (Objects.nonNull(leaveRedPacketRule)) {
                    if (CalculatePayConstant.UNIT_DAY.equals(leaveRedPacketRule.getUnits())) {
                        redNumber = proportionNumberDay.get(i);
                    } else {
                        redNumber = proportionNumberHour.get(i);
                    }
                }
                // 没有设置最后阶段限制则直接计算
                if (salaryCalculateRuleDO.getEndAstrict() == null || salaryCalculateRuleDO.getEndAstrict() != 1
                        || StrKit.isEmpty(salaryCalculateRuleDO.getEndAstrictJson())) {
                    // 使用离职规则
                    BigDecimal number = numbersLeave.get(i);
                    MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                            thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                            redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                            initialPaySum, withholdSum, withhold, redNumber);
                    // 计算累计薪资
                    initialPaySum = moneyNumber.getInitialPaySum();
                    // 计算累计红包
                    redPacketSum = moneyNumber.getRedPacketSum();
                    // 计算累计扣款
                    withholdSum = moneyNumber.getWithholdSum();
                    // 如果是比例分润则计算比例抽成
                    if (!CollectionUtils.isEmpty(leaveOfficeRuleList)) {
                        BigDecimal commissionRatio = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                        if (workerSalary != null && !workerSalary.equals(new BigDecimal(0))
                                && new Integer("3").equals(salaryCalculateRuleDO.getLeaveShowType()) ) {
                            BigDecimal serviceFeeWork = workerSalary.multiply(commissionRatio).
                                    divide(new BigDecimal("100"), 4, BigDecimal.ROUND_DOWN);
                            initialPaySum = initialPaySum.add(serviceFeeWork);
                        }
                        // 计算抽成比例时  红包的计算
                        if (Objects.nonNull(leaveRedPacketRule)) {
                            if (CalculatePayConstant.UNIT_DAY.equals(leaveRedPacketRule.getUnits())) {
                                number = proportionNumberLeaveDay.get(i);
                            } else {
                                number = proportionNumberLeaveHour.get(i);
                            }
                            redPacketSum = calculateRedPackerAmount(leaveRedPacketRule, thisEndTime, entryTime, number,
                                    redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
                        }
                    }
                }
                // 设置了最后阶段限制则分段计算(设置的单位为月时，则相当于没有设置)
                else {
                    // 最后阶段才使用离职规则，其他阶段使用基础规则
                    EndAstrict endAstrict = JSON.parseObject(salaryCalculateRuleDO.getEndAstrictJson(), EndAstrict.class);
                    // 判断单位
                    if (endAstrict.getUnit().equals(CalculatePayConstant.UNIT_MONTH)) {
                        // 无法判断上月多发了多少  所以单位为月时不管设置的多少月  本月都直接使用离职规则
                        BigDecimal number = numbersLeave.get(i);
                        MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                initialPaySum, withholdSum, withhold, redNumber);
                        // 计算累计薪资
                        initialPaySum = moneyNumber.getInitialPaySum();
                        // 计算累计红包
                        redPacketSum = moneyNumber.getRedPacketSum();
                        // 计算累计扣款
                        withholdSum = moneyNumber.getWithholdSum();
                        // 如果是比例分润则计算比例抽成
                        if (!CollectionUtils.isEmpty(leaveOfficeRuleList)) {
                            BigDecimal commissionRatio = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                            if (workerSalary != null && !workerSalary.equals(new BigDecimal(0))
                                    && new Integer("3").equals(salaryCalculateRuleDO.getLeaveShowType())) {
                                BigDecimal serviceFeeWork = workerSalary.multiply(commissionRatio).
                                        divide(new BigDecimal("100"), 4, BigDecimal.ROUND_DOWN);
                                initialPaySum = initialPaySum.add(serviceFeeWork);
                            }
                            // 计算抽成比例时  红包的计算
                            if (Objects.nonNull(leaveRedPacketRule)) {
                                if (CalculatePayConstant.UNIT_DAY.equals(leaveRedPacketRule.getUnits())) {
                                    number = proportionNumberLeaveDay.get(i);
                                } else {
                                    number = proportionNumberLeaveHour.get(i);
                                }
                                redPacketSum = calculateRedPackerAmount(leaveRedPacketRule, thisEndTime, entryTime, number,
                                        redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
                            }
                        }
                    } else if (endAstrict.getUnit().equals(CalculatePayConstant.UNIT_DAY)) {
                        // 如果规则为记天制则计算
                        if (CalculatePayConstant.SHOW_TYPE_MAN_DAY.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                            BigDecimal number = numbersLeave.get(i);
                            // 如果本月的数值小于等于当前的设置值  则本月的薪资按照离职算
                            // 并且数值差按照离职和正常都算一遍，然后用薪资减去两个的差值，就是当前月的薪资(负数返回0)
                            if (number.compareTo(endAstrict.getNumber()) <= 0) {
                                BigDecimal difNumber = endAstrict.getNumber().subtract(number);
                                // 先计算本月离职薪资
                                BigDecimal leaveMoneyNumberSum;
                                BigDecimal hourAmount = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                                leaveMoneyNumberSum = number.multiply(hourAmount);
                                // 计算差值的离职薪资
                                BigDecimal leaveMoneyNumber = difNumber.multiply(hourAmount);
                                // 计算差值的正常工时薪资
                                BigDecimal noMoneyNumber = new BigDecimal("0");
                                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                                    hourAmount = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                                    noMoneyNumber = difNumber.multiply(hourAmount);
                                }
                                leaveMoneyNumberSum = leaveMoneyNumberSum.add(leaveMoneyNumber)
                                        .subtract(noMoneyNumber);
                                // 负数则为0
                                if (leaveMoneyNumberSum.compareTo(new BigDecimal("0")) < 0) {
                                    leaveMoneyNumberSum = new BigDecimal("0");
                                }
                                // 工时薪资累加
                                initialPaySum = initialPaySum.add(leaveMoneyNumberSum);
                                // 红包及扣款
                                MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                // 累计红包
                                redPacketSum = moneyNumber.getRedPacketSum();
                                // 累计扣款
                                withholdSum = moneyNumber.getWithholdSum();

                            } else {
                                // 如果本月的数值大于当前的设置值  则工时工资:设置值按照离职算 差值按照正常算 加起来(红包和倒扣按照离职规则计算)
                                // 工时薪资 先算离职部分
                                BigDecimal difNumber = number.subtract(endAstrict.getNumber());
                                MoneyNumber moneyNumber = leaveRule(endAstrict.getNumber(), leaveOfficeRuleList.get(0), null,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        null, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                initialPaySum = moneyNumber.getInitialPaySum();
                                // 计算正常部分
                                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                                    BigDecimal hourAmount = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                                    initialPaySum = initialPaySum.add(difNumber.multiply(hourAmount));
                                }
                                // 红包部分
                                moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                redPacketSum = moneyNumber.getRedPacketSum();
                                // 扣款部分
                                withholdSum = moneyNumber.getWithholdSum();
                            }
                        }
                        // 直接使用离职规则
                        else {
                            BigDecimal number = numbersLeave.get(i);
                            MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                    thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                    redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                    initialPaySum, withholdSum, withhold, redNumber);
                            // 计算累计薪资
                            initialPaySum = moneyNumber.getInitialPaySum();
                            // 计算累计红包
                            redPacketSum = moneyNumber.getRedPacketSum();
                            // 计算累计扣款
                            withholdSum = moneyNumber.getWithholdSum();
                            // 如果是比例分润则计算比例抽成
                            if (!CollectionUtils.isEmpty(leaveOfficeRuleList)) {
                                BigDecimal commissionRatio = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                                if (workerSalary != null && !workerSalary.equals(new BigDecimal(0))
                                        && new Integer("3").equals(salaryCalculateRuleDO.getLeaveShowType())) {
                                    BigDecimal serviceFeeWork = workerSalary.multiply(commissionRatio).
                                            divide(new BigDecimal("100"), 4, BigDecimal.ROUND_DOWN);
                                    initialPaySum = initialPaySum.add(serviceFeeWork);
                                }
                                // 计算抽成比例时  红包的计算
                                if (Objects.nonNull(leaveRedPacketRule)) {
                                    if (CalculatePayConstant.UNIT_DAY.equals(leaveRedPacketRule.getUnits())) {
                                        number = proportionNumberLeaveDay.get(i);
                                    } else {
                                        number = proportionNumberLeaveHour.get(i);
                                    }
                                    redPacketSum = calculateRedPackerAmount(leaveRedPacketRule, thisEndTime, entryTime, number,
                                            redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
                                }
                            }
                        }
                    } else {
                        // 如果规则为记时制则计算
                        if (CalculatePayConstant.SHOW_TYPE_MAN_HOUR.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                            BigDecimal number = numbersLeave.get(i);
                            // 如果本月的数值小于等于当前的设置值  则本月的薪资按照离职算
                            // 并且数值差按照离职和正常都算一遍，然后用薪资减去两个的差值，就是当前月的薪资(负数返回0)
                            if (number.compareTo(endAstrict.getNumber()) <= 0) {
                                BigDecimal difNumber = endAstrict.getNumber().subtract(number);
                                // 先计算本月离职薪资
                                BigDecimal leaveMoneyNumberSum;
                                BigDecimal hourAmount = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                                leaveMoneyNumberSum = number.multiply(hourAmount);
                                // 计算差值的离职薪资
                                BigDecimal leaveMoneyNumber = difNumber.multiply(hourAmount);
                                // 计算差值的正常工时薪资
                                BigDecimal noMoneyNumber = new BigDecimal("0");
                                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                                    hourAmount = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                                    noMoneyNumber = difNumber.multiply(hourAmount);
                                }
                                leaveMoneyNumberSum = leaveMoneyNumberSum.add(leaveMoneyNumber)
                                        .subtract(noMoneyNumber);
                                // 负数则为0
                                if (leaveMoneyNumberSum.compareTo(new BigDecimal("0")) < 0) {
                                    leaveMoneyNumberSum = new BigDecimal("0");
                                }
                                // 工时薪资累加
                                initialPaySum = initialPaySum.add(leaveMoneyNumberSum);
                                // 红包及扣款
                                MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                // 累计红包
                                redPacketSum = moneyNumber.getRedPacketSum();
                                // 累计扣款
                                withholdSum = moneyNumber.getWithholdSum();

                            } else {
                                // 如果本月的数值大于当前的设置值  则工时工资:设置值按照离职算 差值按照正常算 加起来(红包和倒扣按照离职规则计算)
                                // 工时薪资 先算离职部分
                                BigDecimal difNumber = number.subtract(endAstrict.getNumber());
                                MoneyNumber moneyNumber = leaveRule(endAstrict.getNumber(), leaveOfficeRuleList.get(0), null,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        null, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                initialPaySum = moneyNumber.getInitialPaySum();
                                // 计算正常部分
                                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                                    BigDecimal hourAmount = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                                    initialPaySum = initialPaySum.add(difNumber.multiply(hourAmount));
                                }
                                // 红包部分
                                moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                        thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                        redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                        initialPaySum, withholdSum, withhold, redNumber);
                                redPacketSum = moneyNumber.getRedPacketSum();
                                // 扣款部分
                                withholdSum = moneyNumber.getWithholdSum();
                            }
                        }
                        // 直接使用离职规则
                        else {
                            BigDecimal number = numbersLeave.get(i);
                            MoneyNumber moneyNumber = leaveRule(number, leaveOfficeRuleList.get(0), leaveRedPacketRule,
                                    thisEndTime, entryTime, manHour, manDay, historyManHour, historyDay,
                                    redPacketRecordList, salaryCalculateRuleDO, redPacketSum,
                                    initialPaySum, withholdSum, withhold, redNumber);
                            // 计算累计薪资
                            initialPaySum = moneyNumber.getInitialPaySum();
                            // 计算累计红包
                            redPacketSum = moneyNumber.getRedPacketSum();
                            // 计算累计扣款
                            withholdSum = moneyNumber.getWithholdSum();
                            // 如果是比例分润则计算比例抽成
                            if (!CollectionUtils.isEmpty(leaveOfficeRuleList)) {
                                BigDecimal commissionRatio = new BigDecimal(leaveOfficeRuleList.get(0).getHourAmount() + "");
                                if (workerSalary != null && !workerSalary.equals(new BigDecimal(0))
                                        && new Integer("3").equals(salaryCalculateRuleDO.getLeaveShowType())) {
                                    BigDecimal serviceFeeWork = workerSalary.multiply(commissionRatio).
                                            divide(new BigDecimal("100"), 4, BigDecimal.ROUND_DOWN);
                                    initialPaySum = initialPaySum.add(serviceFeeWork);
                                }
                                // 计算抽成比例时  红包的计算
                                if (Objects.nonNull(leaveRedPacketRule)) {
                                    if (CalculatePayConstant.UNIT_DAY.equals(leaveRedPacketRule.getUnits())) {
                                        number = proportionNumberLeaveDay.get(i);
                                    } else {
                                        number = proportionNumberLeaveHour.get(i);
                                    }
                                    redPacketSum = calculateRedPackerAmount(leaveRedPacketRule, thisEndTime, entryTime, number,
                                            redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
                                }
                            }
                        }
                    }
                }
            }
            else {
                // 使用基础规则
                BigDecimal number = numbers.get(i);
                // 计算薪资
                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                    BigDecimal hourAmount = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                    initialPaySum = initialPaySum.add(number.multiply(hourAmount));
                }
                // 计算红包
                if (Objects.nonNull(normalPacketRule)) {
                    if (CalculatePayConstant.UNIT_DAY.equals(normalPacketRule.getUnits())) {
                        number = proportionNumberDay.get(i);
                    } else {
                        number = proportionNumberHour.get(i);
                    }
                    redPacketSum = calculateRedPackerAmount(normalPacketRule, thisEndTime, entryTime, number,
                            redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
                }
                // 如果是比例分润则计算比例抽成
                if (!CollectionUtils.isEmpty(hourAmountRuleList)) {
                    BigDecimal commissionRatio = new BigDecimal(hourAmountRuleList.get(0).getHourAmount() + "");
                    if (workerSalary != null && !workerSalary.equals(new BigDecimal(0))
                            && new Integer("3").equals(salaryCalculateRuleDO.getShowType()) ) {
                        BigDecimal serviceFeeWork = workerSalary.multiply(commissionRatio).
                                divide(new BigDecimal("100"), 4, BigDecimal.ROUND_DOWN);
                        initialPaySum = initialPaySum.add(serviceFeeWork);
                    }
//                    if (Objects.nonNull(normalPacketRule)) {
//                        if (CalculatePayConstant.UNIT_DAY.equals(normalPacketRule.getUnits())) {
//                            number = proportionNumberDay.get(i);
//                        } else {
//                            number = proportionNumberHour.get(i);
//                        }
//                        redPacketSum = calculateRedPackerAmount(normalPacketRule, thisEndTime, entryTime, number,
//                                redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
//                    }
                }
            }
        }
        initialPaySum = initialPaySum.setScale(4,BigDecimal.ROUND_DOWN);
        redPacketSum = redPacketSum.setScale(4,BigDecimal.ROUND_DOWN);
        withholdSum = withholdSum.setScale(4,BigDecimal.ROUND_DOWN);
        if (ruleType == CalculatePayConstant.RULE_TYPE_MAN_HOUR) {
            // 工时薪资
            calculatePayVO.setWorkTimeRake(initialPaySum);
            // 发放红包记录
            calculatePayVO.setIsAmountRedPacket(JSON.toJSONString(redPacketRecordList));
            // 发放的红包（红包加上倒扣的钱）
            calculatePayVO.setSpecialFee(redPacketSum.add(withholdSum.negate()));
            // 一次性费用（红包加上倒扣的钱）
            calculatePayVO.setOneTimeFee(redPacketSum.add(withholdSum.negate()));
            // 计算总和：薪资 + 红包 - 扣款
            calculatePayVO.setAmount(initialPaySum.add(redPacketSum).subtract(withholdSum)
                    .setScale(4, BigDecimal.ROUND_DOWN));
            // 工价规则名称
            calculatePayVO.setAmountName(salaryCalculateRuleGroupVO.getName());
        }
        else if (ruleType == CalculatePayConstant.RULE_TYPE_COMMISSION) {
            // 工时抽成
            calculatePayVO.setServiceFeeWorkTimeRake(initialPaySum);
            // 发放红包记录
            calculatePayVO.setIsServiceFeeRedPacket(JSON.toJSONString(redPacketRecordList));
            // 发放的红包
            calculatePayVO.setServiceFeeSpecialFee(redPacketSum);
            // 一次性费用（没有）
            calculatePayVO.setServiceFeeOneTimeFee(new BigDecimal("0"));
            // 计算总和：薪资 + 红包
            calculatePayVO.setServiceFee(initialPaySum.add(redPacketSum)
                    .setScale(4, BigDecimal.ROUND_DOWN));
            // 劳务费规则名称
            calculatePayVO.setServiceFeeName(salaryCalculateRuleGroupVO.getName());
        }
    }

    /**
     * 匹配本次使用的规则
     *
     * @param salaryCalculateRuleDOList    规则组中的全部规则
     * @param salaryCalculateRuleUseDOList 使用的规则
     * @param thisEndTime                  本次结束时间
     * @param entryTime                    入职时间
     * @param manHour                      本次工时
     * @param historyManHour               历史工时
     * @param manDay                       本次出勤天数
     * @param historyDay                   历史天数
     * @param thisStartTime                本次开始时间
     */
    private void matchingRule(List<SalaryCalculateRuleDO> salaryCalculateRuleDOList,
                              List<SalaryCalculateRuleDO> salaryCalculateRuleUseDOList,
                              String thisEndTime, String entryTime,
                              BigDecimal manHour, BigDecimal historyManHour,
                              BigDecimal manDay, BigDecimal historyDay,
                              String thisStartTime) {
        if (salaryCalculateRuleDOList.size() == 1) {
            // 只设置了一个规则，则直接使用
            salaryCalculateRuleUseDOList.addAll(salaryCalculateRuleDOList);
        } else {
            for (SalaryCalculateRuleDO salaryCalculateRuleDO : salaryCalculateRuleDOList) {
                String timeJson = salaryCalculateRuleDO.getTimeJson();
                // 如果查询到了长期
                if (StrKit.isEmpty(timeJson)) {
                    salaryCalculateRuleUseDOList.add(salaryCalculateRuleDO);
                    break;
                }
                TimeStart timeStart = JSON.parseObject(timeJson, TimeStart.class);
                if (timeStart.getType() == 1) {
                    // 按时间
                    if (timeStart.getUnit() == 1) {
                        // 单位为月则  判断当前员工的入职时间和本次结束时间（离职则使用离职时间）是否满足当前区间
                        BigDecimal startNumber = timeStart.getStartNumber();
                        BigDecimal endNumber = timeStart.getEndNumber() == null ?
                                new BigDecimal("876000") : timeStart.getEndNumber();
                        int monthNum = getMonthDiff(thisEndTime, entryTime) + 1;
                        if (monthNum >= startNumber.intValue() && monthNum <= endNumber.intValue()) {
                            salaryCalculateRuleUseDOList.add(salaryCalculateRuleDO);
                        }
                    } else if (timeStart.getUnit() == 2) {
                        // 单位为天则  判断当前员工的历史出勤天数和本月出勤天数在哪个区间
                        BigDecimal startNumber = timeStart.getStartNumber();
                        BigDecimal endNumber = timeStart.getEndNumber() == null ?
                                new BigDecimal("36500") : timeStart.getEndNumber();
                        if (historyDay.compareTo(endNumber) < 0 &&
                                manDay.add(historyDay).compareTo(startNumber) >= 0) {
                            salaryCalculateRuleUseDOList.add(salaryCalculateRuleDO);
                        }
                    } else {
                        // 单位为工时则  判断当前员工的历史工时和本月工时在哪个区间
                        BigDecimal startNumber = timeStart.getStartNumber();
                        BigDecimal endNumber = timeStart.getEndNumber() == null ?
                                new BigDecimal("876000") : timeStart.getEndNumber();
                        if (historyManHour.compareTo(endNumber) < 0 &&
                                manHour.add(historyManHour).compareTo(startNumber) >= 0) {
                            salaryCalculateRuleUseDOList.add(salaryCalculateRuleDO);
                        }
                    }
                } else {
                    // 按日期  本次开始时间大于设置的开始时间 并且 小于设置的结束时间
                    String startTime = timeStart.getStartTime();
                    String endTime = timeStart.getEndTime() == null ? "2100-01-01" : timeStart.getEndTime();
                    if (DateKit8.parseDate(thisStartTime).getTime() >= DateKit8.parseDate(startTime).getTime()
                            && DateKit8.parseDate(thisStartTime).getTime() <= DateKit8.parseDate(endTime).getTime()) {
                        salaryCalculateRuleUseDOList.add(salaryCalculateRuleDO);
                    }
                }
            }
        }
    }

    /**
     * 根据使用的规则  构造分段计算的工时和分段计算的出勤天数
     * @param salaryCalculateRuleUseDOList 本次使用的规则
     * @param manHour 当月工时
     * @param historyManHour 历史工时
     * @param manDay 当月出勤天数
     * @param historyDay 历史出勤天数
     * @param numbers 基本规则使用的数值段
     * @param numbersLeave 离职规则使用的数值段
     * @param proportionNumberDays 比例分润时红包单位为天时使用的数值
     * @param proportionNumberHours 比例分润时红包单位为小时使用的数值
     */
    private void subsection(List<SalaryCalculateRuleDO> salaryCalculateRuleUseDOList,
                            BigDecimal manHour, BigDecimal historyManHour,
                            BigDecimal manDay, BigDecimal historyDay,
                            List<BigDecimal> numbers, List<BigDecimal> numbersLeave,
                            List<BigDecimal> proportionNumberDays, List<BigDecimal> proportionNumberHours,
                            List<BigDecimal> proportionNumberLeaveDays, List<BigDecimal> proportionNumberLeaveHours) {
        for (SalaryCalculateRuleDO salaryCalculateRuleDO : salaryCalculateRuleUseDOList) {
            BigDecimal number;
            BigDecimal numberLeave;
            BigDecimal proportionNumberDay = new BigDecimal("0");
            BigDecimal proportionNumberHour = new BigDecimal("0");
            BigDecimal proportionNumberLeaveDay = new BigDecimal("0");
            BigDecimal proportionNumberLeaveHour = new BigDecimal("0");
            TimeStart timeStart = JSON.parseObject(salaryCalculateRuleDO.getTimeJson(), TimeStart.class);
            if (Objects.isNull(timeStart)) {
                timeStart = new TimeStart();
                timeStart.setStartNumber(new BigDecimal("1"));
                timeStart.setEndNumber(new BigDecimal("876000"));
            }  else {
                // 按时间或者单位为月时：本次数值全部使用该规则计算
                if (CalculatePayConstant.TIME_START_TYPE_DAY.equals(timeStart.getType())
                        || CalculatePayConstant.UNIT_MONTH.equals(timeStart.getUnit())) {
                    if (CalculatePayConstant.SHOW_TYPE_MAN_DAY.equals(salaryCalculateRuleDO.getShowType())) {
                        // 计天制
                        number = manDay;
                    } else if (CalculatePayConstant.SHOW_TYPE_MAN_HOUR.equals(salaryCalculateRuleDO.getShowType())) {
                        // 计时制
                        number = manHour;
                    } else {
                        // 比例分润
                        number = new BigDecimal("0");
                    }
                    proportionNumberHour = manHour;
                    proportionNumberDay = manDay;
                    numbers.add(number);
                    proportionNumberHours.add(proportionNumberHour);
                    proportionNumberDays.add(proportionNumberDay);
                    if (CalculatePayConstant.SHOW_TYPE_MAN_DAY.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                        // 计天制
                        numberLeave = manDay;
                    } else if (CalculatePayConstant.SHOW_TYPE_MAN_HOUR.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                        // 计时制
                        numberLeave = manHour;
                    } else {
                        // 比例分润
                        numberLeave = new BigDecimal("0");
                    }
                    proportionNumberLeaveHour = manHour;
                    proportionNumberLeaveDay = manDay;
                    numbersLeave.add(numberLeave);
                    proportionNumberLeaveHours.add(proportionNumberLeaveHour);
                    proportionNumberLeaveDays.add(proportionNumberLeaveDay);
                    continue;
                }
            }
            BigDecimal startNumber = timeStart.getStartNumber();
            BigDecimal endNumber = timeStart.getEndNumber() == null ?
                    new BigDecimal("876000") : timeStart.getEndNumber();
            if (CalculatePayConstant.SHOW_TYPE_MAN_DAY.equals(salaryCalculateRuleDO.getShowType())) {
                // 计天制
                number = calNumber(manDay, historyDay, startNumber, endNumber);
            } else if (CalculatePayConstant.SHOW_TYPE_MAN_HOUR.equals(salaryCalculateRuleDO.getShowType())) {
                // 计时制
                number = calNumber(manHour, historyManHour, startNumber, endNumber);
            } else {
                // 比例分润
                number = new BigDecimal("0");
            }
            proportionNumberHour = calNumber(manHour, historyManHour, startNumber, endNumber);
            proportionNumberDay = calNumber(manDay, historyDay, startNumber, endNumber);
            numbers.add(number);
            proportionNumberHours.add(proportionNumberHour);
            proportionNumberDays.add(proportionNumberDay);
            if (CalculatePayConstant.SHOW_TYPE_MAN_DAY.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                // 计天制
                numberLeave = calNumber(manDay, historyDay, startNumber, endNumber);
            } else if (CalculatePayConstant.SHOW_TYPE_MAN_HOUR.equals(salaryCalculateRuleDO.getLeaveShowType())) {
                // 计时制
                numberLeave = calNumber(manHour, historyManHour, startNumber, endNumber);
            } else {
                // 比例分润
                numberLeave = new BigDecimal("0");
            }
            proportionNumberLeaveHour = calNumber(manHour, historyManHour, startNumber, endNumber);
            proportionNumberLeaveDay = calNumber(manDay, historyDay, startNumber, endNumber);
            numbersLeave.add(numberLeave);
            proportionNumberLeaveHours.add(proportionNumberLeaveHour);
            proportionNumberLeaveDays.add(proportionNumberLeaveDay);
        }
    }

    /**
     * 离职规则计算
     *
     * @param number                需要计算的数值
     * @param leaveOfficeRule       离职规则
     * @param redPacketRule         红包规则
     * @param thisEndTime           本次结束时间
     * @param entryTime             入职时间
     * @param manHour               本次工时
     * @param manDay                本次出勤天数
     * @param historyManHour        历史工时
     * @param historyDay            历史出勤天数
     * @param redPacketRecordList   红包发放记录
     * @param salaryCalculateRuleDO 当前使用的规则（原子规则）
     * @param redPacketSum          累计红包
     * @param initialPaySum         累计薪资
     * @param withholdSum           累计扣款
     * @param withhold              本次扣款
     * @return 计算后的薪资
     */
    private MoneyNumber leaveRule(BigDecimal number, LeaveOfficeRule leaveOfficeRule,
                                  RedPacketRule redPacketRule,
                                  String thisEndTime, String entryTime,
                                  BigDecimal manHour, BigDecimal manDay,
                                  BigDecimal historyManHour, BigDecimal historyDay,
                                  List<RedPacketRecord> redPacketRecordList, SalaryCalculateRuleDO salaryCalculateRuleDO,
                                  BigDecimal redPacketSum, BigDecimal initialPaySum,
                                  BigDecimal withholdSum, BigDecimal withhold, BigDecimal redNumber) {

        MoneyNumber moneyNumber = new MoneyNumber();
        // 计算薪资
        BigDecimal hourAmount = new BigDecimal(leaveOfficeRule.getHourAmount() + "");
        initialPaySum = initialPaySum.add(number.multiply(hourAmount));
        // 计算累计红包
        if (Objects.nonNull(redPacketRule)) {
            redPacketSum = calculateRedPackerAmount(redPacketRule, thisEndTime, entryTime, redNumber,
                    redPacketRecordList, salaryCalculateRuleDO, redPacketSum);
        }
        // 计算累计扣款
        withholdSum = withholdSum.add(withhold);
        // 返回结果
        moneyNumber.setInitialPaySum(initialPaySum);
        moneyNumber.setRedPacketSum(redPacketSum);
        moneyNumber.setWithholdSum(withholdSum);
        return moneyNumber;
    }

    /**
     * 计算该阶段的工时或者出勤天数
     *
     * @param manNum      工时或者出勤天数
     * @param historyNum  历史工时或者历史出勤天数
     * @param startNumber 左边界值
     * @param endNumber   右边界值
     * @return 数值
     */
    private BigDecimal calNumber(BigDecimal manNum, BigDecimal historyNum,
                                 BigDecimal startNumber, BigDecimal endNumber) {
        BigDecimal number;
        boolean isDa = historyNum.add(manNum).compareTo(endNumber) >= 0;
        BigDecimal hisAddThisSubStart = historyNum.add(manNum).subtract(startNumber);
        if (historyNum.compareTo(startNumber) >= 0) {
            if (isDa) {
                // 历史大于等于左边界 && 相加大于等于右边界	则：右边界 - 历史
                number = endNumber.subtract(historyNum);
            } else {
//                 历史大于等于左边界 && 相加小于右边界		则：（相加 - 左边界）- 1
                // 则直接使用当月工时或者出勤天数
                number = manNum;
//                number = hisAddThisSubStart.subtract(new BigDecimal("1"));
            }
        } else {
            if (isDa) {
                // 历史小于左边界 && 相加大于等于右边界		则：（右边界 - 左边界） + 1
                number = endNumber.subtract(startNumber).add(new BigDecimal("1"));
            } else {
                // 历史小于左边界 && 相加小于右边界			则：（相加 - 左边界） + 1
                number = hisAddThisSubStart.add(new BigDecimal("1"));
            }
        }
        return number;
    }

    /**
     * 计算红包
     *
     * @param redPacketRule         红包规则
     * @param thisEndTime           本次结束时间
     * @param entryTime             入职时间
     * @param number                当前阶段使用数值
     * @param redPacketRecordList   红包发放记录
     * @param salaryCalculateRuleDO 当前使用的规则（原子规则）
     * @param redPacketSum          累计红包
     * @return 经过该规则后的累计红包
     */
    private BigDecimal calculateRedPackerAmount(RedPacketRule redPacketRule, String thisEndTime, String entryTime,
                                                BigDecimal number,
                                                List<RedPacketRecord> redPacketRecordList, SalaryCalculateRuleDO salaryCalculateRuleDO,
                                                BigDecimal redPacketSum) {
        int sumRedPackNum;
        // 判断单位
        if (redPacketRule.getUnits().equals(CalculatePayConstant.UNIT_MONTH)) {
            // 月
            int num = getMonthDiff(thisEndTime, entryTime);
            if (redPacketRule.getNumber().compareTo(new BigDecimal("0")) <= 0) {
                num += 1;
                redPacketRule.setNumber(new BigDecimal("1"));
            }
            // 不计算累计，单位为月是只需要判断入职日期到本次结束是否满一个月
            if (num > 1) {
                num = 1;
            }
            sumRedPackNum = new BigDecimal(num + "")
                    .divide(redPacketRule.getNumber(), 0, BigDecimal.ROUND_DOWN).intValue();
        } else if (redPacketRule.getUnits().equals(CalculatePayConstant.UNIT_DAY)) {
            // 天   总计红包应发数量：（当月天数 + 历史天数）/ 设置的数值   注：取整
            sumRedPackNum = number
                    .divide(redPacketRule.getNumber(), 0, BigDecimal.ROUND_DOWN).intValue();
        } else {
            // 工时   总计红包应发数量：（当月工时 + 历史工时）/ 设置的数值   注：取整
            sumRedPackNum = number
                    .divide(redPacketRule.getNumber(), 0, BigDecimal.ROUND_DOWN).intValue();
        }
        // 查询该员工是否发放过红包 如果发放过需要减去已发放的
        int sentRedPackNum = 0;
        /// 按照历史值和当前值，和红包发放记录发放红包，需要把上方的number变成 历史+当前
//        boolean isAddRedPacketRecord = true;
//        for (RedPacketRecord redPacketRecord : redPacketRecordList) {
//            if (salaryCalculateRuleDO.getId().equals(redPacketRecord.getSalaryCalculateRuleId())
//                    && CalculatePayConstant.CALCULATE_TYPE_LEAVE.equals(redPacketRecord.getCalculateType())) {
//                // 找到对应红包发放记录则修改数量
//                sentRedPackNum = redPacketRecord.getNumber();
//                redPacketRecord.setNumber(sumRedPackNum);
//                isAddRedPacketRecord = false;
//                break;
//            }
//        }
//        if (isAddRedPacketRecord) {
//            // 没找到对应的红包发放记录则新增
//            RedPacketRecord redPacketRecord = new RedPacketRecord();
//            redPacketRecord.setNumber(sumRedPackNum);
//            redPacketRecord.setSalaryCalculateRuleId(salaryCalculateRuleDO.getId());
//            redPacketRecord.setCalculateType(CalculatePayConstant.CALCULATE_TYPE_LEAVE);
//            redPacketRecordList.add(redPacketRecord);
//        }
        redPacketSum = new BigDecimal(sumRedPackNum - sentRedPackNum)
                .multiply(new BigDecimal(redPacketRule.getRedPacketAmount() + ""))
                .add(redPacketSum);
        return redPacketSum;
    }

    /**
     * 获取两个日期相差的月数
     *
     * @param endTime   较大的日期
     * @param startTime 较小的日期
     * @return 如果d1>d2返回 月数差 否则返回0
     */
    private int getMonthDiff(String endTime, String startTime) {
        Date d1 = DateKit8.parseDate(endTime);
        Date d2 = DateKit8.parseDate(startTime);
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(d1);
        c2.setTime(d2);
        if (c1.getTimeInMillis() < c2.getTimeInMillis()) {
            return 0;
        }
        int year1 = c1.get(Calendar.YEAR);
        int year2 = c2.get(Calendar.YEAR);
        int month1 = c1.get(Calendar.MONTH);
        int month2 = c2.get(Calendar.MONTH);
        int day1 = c1.get(Calendar.DAY_OF_MONTH);
        int day2 = c2.get(Calendar.DAY_OF_MONTH);
        // 获取年的差值 假设 d1 = 2015-8-16 d2 = 2011-9-30
        int yearInterval = year1 - year2;
        // 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
        boolean yearDown = month1 < month2 || month1 == month2 && day1 < day2;
        if (yearDown) {
            yearInterval--;
        }
        // 获取月数差值
        int monthInterval = (month1 + 12) - month2;
        if (day1 < day2) {
            monthInterval--;
        }
        monthInterval %= 12;
        return yearInterval * 12 + monthInterval;
    }


}
